/**
 * 强势调整QSTZ 众赢投顾 主图指标
 */

import {movingAverage as _average} from './MA'
import * as zytgTools from './ZYTG_UTIL'

const QSTZ_SAFE_AVERAGE_PERIOD = 60    //强势调整的安全均线周期
const QSTZ_TuPo_BOTTOM_DEVIATION = 0.66    //回调判断位置
const QSTZ_TuPo_A_TOP_DEVIATION = 1.11       //A类突破判断位置
const QSTZ_TuPo_B_TOP_DEVIATION = 1.05       //区间突破结束判断位置
const QSTZ_HuiTiao_UP_DEVIATION = 1.05       //回调反弹范围
const QSTZ_HuiTiao_DEVIATION = 0.9         //回调判断位置
const QSTZ_SAFE_DEVIATION_RANGE = 0.07 //安全振幅
const QSTZ_START_K_FOR_TuPo_A = 2      //A类突破起算K线
const QSTZ_START_K_FOR_TuPo_B = 2      //B类突破起算K线 
const QSTZ_MAX_FALLING_K_COUNT = 10    //涨停后高点回落K线最大数量
const QSTZ_MAX_K_COUNT = 20            //涨停后K线最大数量
const QSTZ_ARROW_COLOR_FOR_TuPo = 'red'        //突破箭头颜色 
const QSTZ_ARROW_COLOR_FOR_HuiTiao = 'blue'    //回调箭头颜色 
const QSTZ_KLINE_COLOR = 'red'                 //涨停k线填充颜色 
const QSTZ_SAFE_LINE_COLOR = 'green'           //保护位线条颜色 
const QSTZ_ARROW_LINE_COLOR = 'purple'           //箭头连线颜色 


let initParam = {
  name: 'QSTZ',
  type: 'polyline',
  caculateParam: [60],  // 默认用
}

/**
 * Caculator 数据处理
 *
 */
/**
 * Caculator 数据处理
 * @param  {array} rawData
 * @param  {array} caculateParam
 * @param  {string} prop //指定计算哪个字段   close 
 * @return {array} 一维数组
 *
 * 使用说明（render.k.chart.js）：
      let qstzData = caclInitData([60], store.data)
      let qstzResult = QSTZCalc.caculate(qstzData) 
 *
 * 数据结构说明
[
  {
    "index": 84,
    "time": "2017-07-07",
    "KLine":
    {
        "start": 105,
        "end": 115.13,
        "color": "red"
    },
    "safeLine":
    {
        "start": 84,
        "price": 104.68,
        "color": "green",
        "end": 94
    },
    "arrows": [
    {
        "index": 86,
        "time": "2017-07-11",
        "color": "blue",
        "price": 106.2
    }],
    "eye":
    {
        "index": 88,
        "time": "2017-07-13",
        "price": 104.68,
        "moveRight": true
    }
  }
]
 */
function caculate (rawData, caculateParam, prop = 'close') {
  // console.log("QSTZ raw data count", rawData.length)

  if (!(rawData instanceof Array)) throw new Error('Data or caculateParam is not Array')
  let period = (caculateParam instanceof Array) ? caculateParam[0] : QSTZ_SAFE_AVERAGE_PERIOD
  let mathData = _caculator(rawData, period, prop)
  return mathData
}

function _caculator (rawData, period, type) {
  let prices = []
  for (let i = 0; i < rawData.length; i++) {
    prices.push(rawData[i][type])
  }
  let averages = _average(prices, period)
  let dataPoints = []
  let point = null
  for (let i = QSTZ_SAFE_AVERAGE_PERIOD - 1; i < averages.length; i++) {
    //出现过过于强势或者回调，则提早退出模式
    let quitCurrentPoint = point && (point.isOverHeat || point.alreadyHuiTiao)

    //出现涨停，且涨停价在60日均线之上
    let startPointFound = zytgTools.ifZhangTing(rawData, i) && (prices[i] > averages[i]);
    //非一字板和T
    startPointFound = startPointFound && (rawData[i]['open'] != rawData[i]['close']) 
    //涨停板与次日成交量相差小于1倍，也就是涨停的量不大于次日量的两倍，也不小于次日成交量的二分之一
    startPointFound = startPointFound && rawData[i+1] && (rawData[i]['volume'] * 2 >= rawData[i+1]['volume']) && (rawData[i]['volume'] <= rawData[i+1]['volume'] * 2) 
    //未来两天内不存在涨停板
    startPointFound = startPointFound && (!zytgTools.ifZhangTing(rawData, i+1)) && (!zytgTools.ifZhangTing(rawData, i+2))

    //涨停后经过k线数量
    let byPassCount = point ? i-point.index : 0
    //高点首次回落1：当天是涨停后高点，且当天未能以高点收盘
    if (point && (rawData[i]['high'] > point.topPrice) && (rawData[i]['high'] > prices[i])) {
      point.fallingIndex = i
    } 
    //高点首次回落2：昨日是涨停后高点，且昨日以高点收盘，且今日收盘低于高点
    if (point && (rawData[i-1]['high'] == point.topPrice) && (rawData[i-1]['high'] == prices[i-1]) && (point.topPrice > prices[i])) {
      point.fallingIndex = i
    } 
    //涨停后高点回落后经过的K线数量
    let fallingCount = (point && point.fallingIndex) ? i-point.fallingIndex : 0
    // if (point) console.log("falling", i, point.fallingIndex, prices[i], point.topPrice, rawData[i]['high'])

    // console.log(byPassCount, QSTZ_MAX_K_COUNT)
    //定位到新的合格涨停，或发现退出模式标识，或已经到达涨停后高点回落10根K线, 或涨停后总k先数量达到20，或已经没有更多k线，结束当前点的处理
    if (startPointFound || quitCurrentPoint || (i == averages.length-1) || (fallingCount == QSTZ_MAX_FALLING_K_COUNT) || (byPassCount == QSTZ_MAX_K_COUNT)) {
      if (point) {
        let eye
        point.safeLine.end = (startPointFound) ? (i-1) : i
        if (point.arrows.length > 0) {
          eye = {}
          let count = point.arrows[point.arrows.length-1].index - point.arrows[0].index
          let moveRight = (count % 2 > 0)
          let center = (count == 0) ? point.arrows[0].index : point.arrows[0].index + Math.floor(count / 2)
          eye.index = center
          eye.time = rawData[center]['time']
          eye.price = point.safeLine.price
          eye.moveRight = moveRight
        }

        dataPoints.push({
          index: point.index,
          time: point.time,
          KLine: point.KLine,
          safeLine: point.safeLine,
          arrows: point.arrows,
          eye: eye
        })
        point = null;
      }
      if (startPointFound) {
        point = {}
        point.index = i
        point.time = rawData[i]['time']
        point.KLine = {start: rawData[i]['open'], end: rawData[i]['close'], color: QSTZ_KLINE_COLOR}
        point.safeLine = {start: i, price: rawData[i]['low'], color: QSTZ_SAFE_LINE_COLOR}
        point.arrows = []
        point.closePrice = prices[i]     
        point.topPrice = prices[i]
      }
    } else if (point) {
      let isArrow = false

      //检查是否A类突破型箭头
      //涨停后第二根K线就开始标注
      let isRedArrowA = (byPassCount >= QSTZ_START_K_FOR_TuPo_A)
      //只要出现过回调，不再关注后续新模式
      isRedArrowA = isRedArrowA && !(point.alreadyHuiTiao)
      //最高价处于涨停价*1.11之下，实体在涨停价之上
      //1.11更改为全局条件(代表过于强势），一旦出现>1.11则放弃整个模式，不再标注
      if (!point.isOverHeat && (rawData[i]['high'] > point.closePrice * QSTZ_TuPo_A_TOP_DEVIATION)) {
        point.isOverHeat = true
        continue
      }
      isRedArrowA = isRedArrowA && (Math.min(rawData[i]['open'], rawData[i]['close']) > point.closePrice) 
      // isRedArrowA = isRedArrowA && ((rawData[i]['high']-rawData[i]['low'])/rawData[i]['open'] < QSTZ_SAFE_DEVIATION_RANGE) 

      //检查是否B类区间突破箭头
      //是否正在处于区间突破中
      let aCount = point.arrows.length;
      let isInRedArrowB = (aCount > 0) && (point.arrows[aCount - 1].index == i - 1) && (point.arrows[aCount - 1].type == 1);
      let isRedArrowB = isInRedArrowB;
      if (!isInRedArrowB && !isRedArrowA) {
        //只要出现过回调，不再关注后续新模式
        isRedArrowB = !(point.alreadyHuiTiao)
        //涨停后第二根开始标注、A类满足的同时不会满足B类
        isRedArrowB = isRedArrowB && (byPassCount >= QSTZ_START_K_FOR_TuPo_B)
      }
      //实体下沿在涨停价之下，并在涨停后高点10%回调位之上，否则不符合标注
      isRedArrowB = isRedArrowB && (Math.min(rawData[i]['open'], rawData[i]['close']) < point.closePrice) 
      isRedArrowB = isRedArrowB && (Math.min(rawData[i]['open'], rawData[i]['close']) > point.topPrice * QSTZ_HuiTiao_DEVIATION) 
      if (isRedArrowB && aCount > 1) {
        //连续两根K线(a1和a2)实体下沿均在涨停价和10%回调位之间
        let LianXuQuJian = (point.arrows[aCount - 1].index == i - 1) && (point.arrows[aCount - 1].type == 1) && (point.arrows[aCount - 2].index == i - 2) && (point.arrows[aCount - 2].type == 1);
        //登记最新组合高点
        if (LianXuQuJian) {
          point.quJianZuHe = { index: i-1, high: Math.max(rawData[i-1]['high'], rawData[i-2]['high'])};
        }
        //组合后一根K线（a3）最高点H2高于前组合高点H1
        let zuHeTuPo = point.quJianZuHe && (rawData[point.quJianZuHe.index + 1]['high'] > point.quJianZuHe.high);
        //某根K线（包括a3）最高点超过了H1*1.05或涨停价*1.11，结束标注
        if (zuHeTuPo && (rawData[i]['high'] > Math.min(point.quJianZuHe.high, point.closePrice) * QSTZ_TuPo_B_TOP_DEVIATION))
          isRedArrowB = false;
      }

      //检查是否回调箭头
      //是否正在处于回调中
      aCount = point.arrows.length;
      let isInBlueArrow = (aCount > 0) && (point.arrows[aCount - 1].index == i - 1) && (point.arrows[aCount - 1].type == 2);
      let isBlueArrow = isInBlueArrow;
      if (!isInBlueArrow) {
        //只要出现过回调，不再关注后续新模式
        isBlueArrow = !(point.alreadyHuiTiao)
        //涨停之后的高点回落10%
        isBlueArrow = isBlueArrow && (rawData[i]['close'] <= point.topPrice * QSTZ_HuiTiao_DEVIATION)
        //收盘价回落至涨停价与涨停底之间
        isBlueArrow = isBlueArrow && (rawData[i]['close'] < point.closePrice) 
        isBlueArrow = isBlueArrow && (rawData[i]['close'] > point.safeLine.price) 
      }
      //当收盘跌破涨停底时结束标注/不再关注是否存在回调模式，退出
      if (rawData[i]['close'] < point.safeLine.price) {
        isBlueArrow = false
        point.alreadyHuiTiao = true
      }
      if (isBlueArrow && isInBlueArrow) {
        // console.log("inBlud", rawData[i]['close'], rawData[i]['high'], point.safeLine.price, point.topPrice, point.topPrice * QSTZ_HuiTiao_DEVIATION * QSTZ_HuiTiao_UP_DEVIATION)
        //当出现回调型信号之后的K线最高点超过10%回调位*1.05时，结束标注（第一根回调k线最高点可以忽略）
        isBlueArrow = isBlueArrow && (rawData[i]['high'] <= point.topPrice * QSTZ_HuiTiao_DEVIATION * QSTZ_HuiTiao_UP_DEVIATION)

        if (!isBlueArrow && !point.alreadyHuiTiao) point.alreadyHuiTiao = true
      }


      //统一登记标注情况
      //当出现回调型信号之后的K线最高点超过10%回调位*1.05时，结束标注
      isRedArrowA = isRedArrowA && !isBlueArrow && !point.alreadyHuiTiao
      isRedArrowB = isRedArrowB && !isBlueArrow && !point.alreadyHuiTiao
      if (isRedArrowA) {
        point.arrows.push({
          index: i,
          time: rawData[i]['time'],
          color: QSTZ_ARROW_COLOR_FOR_TuPo,
          price: rawData[i]['low'],
          type: 0
        })
      }
      if (isRedArrowB) {
        point.arrows.push({
          index: i,
          time: rawData[i]['time'],
          color: QSTZ_ARROW_COLOR_FOR_TuPo,
          price: rawData[i]['low'],
          type: 1
        })
      }
      if (isBlueArrow) {
        point.arrows.push({
          index: i,
          time: rawData[i]['time'],
          color: QSTZ_ARROW_COLOR_FOR_HuiTiao,
          price: rawData[i]['low'],
          type: 2
        })
      }

      point.topPrice = Math.max(point.topPrice, rawData[i]['high'])
    }
  }
  // console.log(JSON.stringify(dataPoints))
  return dataPoints
}


export default {
  initParam: initParam,
  caculate: caculate
}
